<!DOCTYPE html>
            
<HTML>
<HEAD>
<meta name="booktitle" content="Developing Applications With Objective Caml" >
 <meta charset="ISO-8859-1"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
<META name="GENERATOR" content="hevea 1.05-7 of 2000-02-24">
<META NAME="Author" CONTENT="Christian.Queinnec@lip6.fr">
<LINK rel=stylesheet type="text/css" href="videoc-ocda.css">
<script language="JavaScript" src="videoc.js"><!--
//--></script>
<TITLE>
 HTTP Servlets
</TITLE>
</HEAD>
<BODY class="regularBody">
<A HREF="book-ora195.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Contents"></A>
<A HREF="book-ora198.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
<HR>

<H2> HTTP Servlets</H2>
A servlet is a ``module'' that can be integrated into a server
application to respond to client requests. Although a servlet need not use a
specific protocol, we will use the HTTP protocol for communication (see figure
<A HREF="book-ora196.html#fig-pdcgiml">21.1</A>). In practice, the term servlet refers to an HTTP servlet.<BR>
<BR>
The classic method of constructing dynamic HTML pages on a server is to use
CGI (Common Gateway Interface) commands. These take as argument a URL which
can contain data coming from an HTML form. The execution then produces a new
HTML page which is sent to the client. The following links describe the HTTP
and CGI protocols.


<H3> Link </H3> <HR>

<A HREF="http://www.cis.ohio-state.edu/cgi-bin/rfc/rfc1945.html">http://www.cis.ohio-state.edu/cgi-bin/rfc/rfc1945.html</A>


<HR>




<H3> Link </H3> <HR>

<A HREF="http://hoohoo.ncsa.uiuc.edu/docs/cgi/overview.html">http://hoohoo.ncsa.uiuc.edu/docs/cgi/overview.html</A>


<HR>


It is a slightly heavyweight mechanism because it launches a new program for
each request.<BR>
<BR>
HTTP servlets are launched just once, and can can decode arguments in CGI
format to execute a request. Servlets can take advantage of the Web browser's
capabilities to construct a graphical interface for an application.<BR>
<BR>
<BLOCKQUOTE><DIV ALIGN=center><HR WIDTH="80%" SIZE=2></DIV>
<DIV ALIGN=center>
<IMG SRC="book-ora083.gif">
</DIV>
<BR>
<DIV ALIGN=center>Figure 21.1: communication between a browser and an Objective CAMLserver</DIV><BR>

<A NAME="fig-pdcgiml"></A>
<DIV ALIGN=center><HR WIDTH="80%" SIZE=2></DIV></BLOCKQUOTE>In this section we will define a server for the HTTP protocol. We will not
handle the entire specification of the protocol, but instead will limit
ourselves to those functions necessary for the implementation of a server that
mimics the behavior of a CGI application.<BR>
<BR>
At an earlier time, we defined a generic server module <TT>Gsd</TT>. Now we
will give the code to create an application of this generic server for
processing part of the HTTP protocol.<BR>
<BR>
<A NAME="toc298"></A>
<H3> HTTP and CGI Formats</H3>We want to obtain a server that imitates the behavior of a CGI application.
One of the first tasks is to decode the format of HTTP requests with CGI
extensions for argument passing.<BR>
<BR>
The clients of this server can be browsers such as Netscape or Internet
Explorer.<BR>
<BR>

<H4> Receiving Requests</H4>
Requests in the HTTP protocol have essentially three components: a method,
a URL and some data. The data must follow a particular format.<BR>
<BR>
In this section we will construct a collection of functions for reading,
decomposing and decoding the components of a request. These functions can
raise the exception:


<PRE><BR># <B>exception</B><CODE> </CODE>Http_error<CODE> </CODE><B>of</B><CODE> </CODE>string<CODE> </CODE>;;<BR><CODE>exception Http_error of string</CODE><BR>

</PRE>
<BR>
<BR>

<H5> Decoding</H5>
The function <TT>decode</TT>, which uses the helper function
<TT>rep_xcode</TT>, attempts to restore the characters which have been
encoded by the HTTP client: spaces (which have been replaced by <TT>+</TT>),
and certain reserved characters which have been replaced by their hexadecimal
code.<BR>
<BR>


<PRE><BR># <B>let</B><CODE> </CODE><B>rec</B><CODE> </CODE>rep_xcode<CODE> </CODE>s<CODE> </CODE>i<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>xs<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>"0x00"</CODE><CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>String.blit<CODE> </CODE>s<CODE> </CODE><TT>(</TT>i<CODE>+</CODE><CODE>1</CODE><TT>)</TT><CODE> </CODE>xs<CODE> </CODE><CODE>2</CODE><CODE> </CODE><CODE>2</CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>String.set<CODE> </CODE>s<CODE> </CODE>i<CODE> </CODE><TT>(</TT>char_of_int<CODE> </CODE><TT>(</TT>int_of_string<CODE> </CODE>xs<TT>)</TT><TT>)</TT>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>String.blit<CODE> </CODE>s<CODE> </CODE><TT>(</TT>i<CODE>+</CODE><CODE>3</CODE><TT>)</TT><CODE> </CODE>s<CODE> </CODE><TT>(</TT>i<CODE>+</CODE><CODE>1</CODE><TT>)</TT><CODE> </CODE><TT>(</TT><TT>(</TT>String.length<CODE> </CODE>s<TT>)</TT><CODE>-</CODE><TT>(</TT>i<CODE>+</CODE><CODE>3</CODE><TT>)</TT><TT>)</TT>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>String.set<CODE> </CODE>s<CODE> </CODE><TT>(</TT><TT>(</TT>String.length<CODE> </CODE>s<TT>)</TT><CODE>-</CODE><CODE>2</CODE><TT>)</TT><CODE> </CODE><CODE>'\000'</CODE>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Printf.printf<CODE>"rep_xcode1(%s)\n"</CODE><CODE> </CODE>s<CODE> </CODE>;;<BR><CODE>val rep_xcode : string -&gt; int -&gt; unit = &lt;fun&gt;</CODE><BR><BR># <B>exception</B><CODE> </CODE>End_of_decode<CODE> </CODE><B>of</B><CODE> </CODE>string<CODE> </CODE>;;<BR><CODE>exception End_of_decode of string</CODE><BR><BR># <B>let</B><CODE> </CODE>decode<CODE> </CODE>s<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>try</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>for</B><CODE> </CODE>i<CODE>=</CODE><CODE>0</CODE><CODE> </CODE><B>to</B><CODE> </CODE>pred<TT>(</TT>String.length<CODE> </CODE>s<TT>)</TT><CODE> </CODE><B>do</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>match</B><CODE> </CODE>s<CODE>.[</CODE>i<CODE>]</CODE><CODE> </CODE><B>with</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>'+'</CODE><CODE> </CODE>-&gt;<CODE> </CODE>s<CODE>.[</CODE>i<CODE>]</CODE><CODE> </CODE><CODE>&lt;-</CODE><CODE> </CODE><CODE>' '</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>|</CODE><CODE> </CODE><CODE>'%'</CODE><CODE> </CODE>-&gt;<CODE> </CODE>rep_xcode<CODE> </CODE>s<CODE> </CODE>i<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>|</CODE><CODE> </CODE><CODE>'\000'</CODE><CODE> </CODE>-&gt;<CODE> </CODE>raise<CODE> </CODE><TT>(</TT>End_of_decode<CODE> </CODE><TT>(</TT>String.sub<CODE> </CODE>s<CODE> </CODE><CODE>0</CODE><CODE> </CODE>i<TT>)</TT><TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>|</CODE><CODE> </CODE><CODE>_</CODE><CODE> </CODE>-&gt;<CODE> </CODE>()<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>done</B>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>s<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>with</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>End_of_decode<CODE> </CODE>s<CODE> </CODE>-&gt;<CODE> </CODE>s<CODE> </CODE>;;<BR><CODE>val decode : string -&gt; string = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>

<H5> String manipulation functions</H5>
The module <TT>String_plus</TT> contains some functions for taking apart
character strings:
<UL>
<LI>
 <TT>prefix</TT> and <TT>suffix</TT>, which extract the substrings to
either side of an index;

<LI> <TT>split</TT>, which returns the list of substrings determined by a
separator character;

<LI> <TT>unsplit</TT>, which concatenates a list of strings, inserting
separator characters between them.
</UL>

<PRE><BR># <B>module</B><CODE> </CODE>String_plus<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><B>struct</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>prefix<CODE> </CODE>s<CODE> </CODE>n<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>try</B><CODE> </CODE>String.sub<CODE> </CODE>s<CODE> </CODE><CODE>0</CODE><CODE> </CODE>n<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>with</B><CODE> </CODE>Invalid_argument<TT>(</TT><CODE>"String.sub"</CODE><TT>)</TT><CODE> </CODE>-&gt;<CODE> </CODE>s<BR><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>suffix<CODE> </CODE>s<CODE> </CODE>i<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>try</B><CODE> </CODE>String.sub<CODE> </CODE>s<CODE> </CODE>i<CODE> </CODE><TT>(</TT><TT>(</TT>String.length<CODE> </CODE>s<TT>)</TT><CODE>-</CODE>i<TT>)</TT><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>with</B><CODE> </CODE>Invalid_argument<TT>(</TT><CODE>"String.sub"</CODE><TT>)</TT><CODE> </CODE>-&gt;<CODE> </CODE><CODE>""</CODE><CODE> </CODE><BR><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE><B>rec</B><CODE> </CODE>split<CODE> </CODE>c<CODE> </CODE>s<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>try</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>i<CODE> </CODE><CODE>=</CODE><CODE> </CODE>String.index<CODE> </CODE>s<CODE> </CODE>c<CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>s1<CODE>,</CODE><CODE> </CODE>s2<CODE> </CODE><CODE>=</CODE><CODE> </CODE>prefix<CODE> </CODE>s<CODE> </CODE>i<CODE>,</CODE><CODE> </CODE>suffix<CODE> </CODE>s<CODE> </CODE><TT>(</TT>i<CODE>+</CODE><CODE>1</CODE><TT>)</TT><CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>s1::<TT>(</TT>split<CODE> </CODE>c<CODE> </CODE>s2<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>with</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Not_found<CODE> </CODE>-&gt;<CODE> </CODE><CODE>[</CODE>s<CODE>]</CODE><CODE> </CODE><BR><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>unsplit<CODE> </CODE>c<CODE> </CODE>ss<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>f<CODE> </CODE>s1<CODE> </CODE>s2<CODE> </CODE><CODE>=</CODE><CODE> </CODE><B>match</B><CODE> </CODE>s2<CODE> </CODE><B>with</B><CODE> </CODE><CODE>""</CODE><CODE> </CODE>-&gt;<CODE> </CODE>s1<CODE> </CODE><CODE>|</CODE><CODE> </CODE><CODE>_</CODE><CODE> </CODE>-&gt;<CODE> </CODE>s1<CODE>^</CODE><TT>(</TT>Char.escaped<CODE> </CODE>c<TT>)</TT><CODE>^</CODE>s2<CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>List.fold_right<CODE> </CODE>f<CODE> </CODE>ss<CODE> </CODE><CODE>""</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE>;;<BR>

</PRE>
<BR>
<BR>

<H5> Decomposing data from a form</H5>
Requests typically arise from an HTML page containing a form. The contents
of the form are transmitted as a character string containing the names and
values associated with the fields of the form. The function
<TT>get_field_pair</TT> transforms such a string into an association
list.<A NAME="get_form_content"></A>


<PRE><BR># <B>let</B><CODE> </CODE>get_field_pair<CODE> </CODE>s<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>match</B><CODE> </CODE>String_plus.split<CODE> </CODE><CODE>'='</CODE><CODE> </CODE>s<CODE> </CODE><B>with</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>[</CODE>n;v<CODE>]</CODE><CODE> </CODE>-&gt;<CODE> </CODE>n<CODE>,</CODE>v<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>|</CODE><CODE> </CODE><CODE>_</CODE><CODE> </CODE>-&gt;<CODE> </CODE>raise<CODE> </CODE><TT>(</TT>Http_error<CODE> </CODE><TT>(</TT><CODE>"Bad field format : "</CODE><CODE>^</CODE>s<TT>)</TT><TT>)</TT><CODE> </CODE>;;<BR><CODE>val get_field_pair : string -&gt; string * string = &lt;fun&gt;</CODE><BR><BR># <B>let</B><CODE> </CODE>get_form_content<CODE> </CODE>s<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>ss<CODE> </CODE><CODE>=</CODE><CODE> </CODE>String_plus.split<CODE> </CODE><CODE>'&amp;'</CODE><CODE> </CODE>s<CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>List.map<CODE> </CODE>get_field_pair<CODE> </CODE>ss<CODE> </CODE>;;<BR><CODE>val get_form_content : string -&gt; (string * string) list = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>

<H5> Reading and decomposing</H5>
The function <TT>get_query</TT> extracts the method and the URL from a
request and stores them in an array of character strings. One can thus use
a standard CGI application which retrieves its arguments from the array of
command-line arguments. The function <TT>get_query</TT> uses the auxiliary
function <TT>get</TT>. We arbitrarily limit requests to a maximum size of
2555 characters.<A NAME="get_query_string"></A>


<PRE><BR># <B>let</B><CODE> </CODE>get<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>buff_size<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE>2</CODE><CODE>5</CODE><CODE>5</CODE><CODE>5</CODE><CODE> </CODE><B>in</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>buff<CODE> </CODE><CODE>=</CODE><CODE> </CODE>String.create<CODE> </CODE>buff_size<CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><TT>(</TT><B>fun</B><CODE> </CODE>ic<CODE> </CODE>-&gt;<CODE> </CODE>String.sub<CODE> </CODE>buff<CODE> </CODE><CODE>0</CODE><CODE> </CODE><TT>(</TT>input<CODE> </CODE>ic<CODE> </CODE>buff<CODE> </CODE><CODE>0</CODE><CODE> </CODE>buff_size<TT>)</TT><TT>)</TT><CODE> </CODE>;;<BR><CODE>val get : in_channel -&gt; string = &lt;fun&gt;</CODE><BR><BR># <B>let</B><CODE> </CODE>query_string<CODE> </CODE>http_frame<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>try</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>i0<CODE> </CODE><CODE>=</CODE><CODE> </CODE>String.index<CODE> </CODE>http_frame<CODE> </CODE><CODE>' '</CODE><CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>q0<CODE> </CODE><CODE>=</CODE><CODE> </CODE>String_plus.prefix<CODE> </CODE>http_frame<CODE> </CODE>i0<CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>match</B><CODE> </CODE>q0<CODE> </CODE><B>with</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>"GET"</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>-&gt;<CODE> </CODE><B>begin</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>i1<CODE> </CODE><CODE>=</CODE><CODE> </CODE>succ<CODE> </CODE>i0<CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>i2<CODE> </CODE><CODE>=</CODE><CODE> </CODE>String.index_from<CODE> </CODE>http_frame<CODE> </CODE>i1<CODE> </CODE><CODE>' '</CODE><CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>q<CODE> </CODE><CODE>=</CODE><CODE> </CODE>String.sub<CODE> </CODE>http_frame<CODE> </CODE>i1<CODE> </CODE><TT>(</TT>i2<CODE>-</CODE>i1<TT>)</TT><CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>try</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>i<CODE> </CODE><CODE>=</CODE><CODE> </CODE>String.index<CODE> </CODE>q<CODE> </CODE><CODE>'?'</CODE><CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>q1<CODE> </CODE><CODE>=</CODE><CODE> </CODE>String_plus.prefix<CODE> </CODE>q<CODE> </CODE>i<CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>q<CODE> </CODE><CODE>=</CODE><CODE> </CODE>String_plus.suffix<CODE> </CODE>q<CODE> </CODE><TT>(</TT>succ<CODE> </CODE>i<TT>)</TT><CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Array.of_list<CODE> </CODE><TT>(</TT>q0::q1::<TT>(</TT>String_plus.split<CODE> </CODE><CODE>' '</CODE><CODE> </CODE><TT>(</TT>decode<CODE> </CODE>q<TT>)</TT><TT>)</TT><TT>)</TT><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>with</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Not_found<CODE> </CODE>-&gt;<CODE> </CODE><CODE>[|</CODE>q0;q<CODE>|]</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>|</CODE><CODE> </CODE><CODE>_</CODE><CODE> </CODE>-&gt;<CODE> </CODE>raise<CODE> </CODE><TT>(</TT>Http_error<CODE> </CODE><TT>(</TT><CODE>"Unsupported method: "</CODE><CODE>^</CODE>q0<TT>)</TT><TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>with</B><CODE> </CODE>e<CODE> </CODE>-&gt;<CODE> </CODE>raise<CODE> </CODE><TT>(</TT>Http_error<CODE> </CODE><TT>(</TT><CODE>"Unknown request: "</CODE><CODE>^</CODE>http_frame<TT>)</TT><TT>)</TT><CODE> </CODE>;;<BR><CODE>val query_string : string -&gt; string array = &lt;fun&gt;</CODE><BR><BR># <B>let</B><CODE> </CODE>get_query_string<CODE> </CODE>ic<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>http_frame<CODE> </CODE><CODE>=</CODE><CODE> </CODE>get<CODE> </CODE>ic<CODE> </CODE><B>in</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>query_string<CODE> </CODE>http_frame;;<BR><CODE>val get_query_string : in_channel -&gt; string array = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>

<H4> The Server</H4>
To obtain a CGI pseudo-server, able to process only the <TT>GET</TT> method, we
write the class <TT>http_servlet</TT>, whose argument <TT>fun_serv</TT> is
a function for processing HTTP requests such as might have been written for a
CGI application.


<PRE><BR># <B>module</B><CODE> </CODE>Text_Server<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Server<CODE> </CODE><TT>(</TT><B>struct</B><CODE> </CODE><B>type</B><CODE> </CODE>t<CODE> </CODE><CODE>=</CODE><CODE> </CODE>string<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>to_string<CODE> </CODE>x<CODE> </CODE><CODE>=</CODE><CODE> </CODE>x<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>of_string<CODE> </CODE>x<CODE> </CODE><CODE>=</CODE><CODE> </CODE>x<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B><TT>)</TT>;;<BR><BR># <B>module</B><CODE> </CODE>P_Text_Server<CODE> </CODE><TT>(</TT>P<CODE> </CODE><CODE>:</CODE><CODE> </CODE>PROTOCOL<TT>)</TT><CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><B>struct</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>module</B><CODE> </CODE>Internal_Server<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Server<CODE> </CODE><TT>(</TT>P<TT>)</TT><BR><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>class</B><CODE> </CODE>http_servlet<CODE> </CODE><CODE> </CODE>n<CODE> </CODE>np<CODE> </CODE>fun_serv<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>object</B><TT>(</TT>self<TT>)</TT><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>inherit</B><CODE> </CODE><CODE>[</CODE>P.t<CODE>]</CODE><CODE> </CODE>Internal_Server.server<CODE> </CODE>n<CODE> </CODE>np<CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><BR><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>receive_h<CODE> </CODE>fd<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>ic<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Unix.in_channel_of_descr<CODE> </CODE>fd<CODE> </CODE><B>in</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>input_line<CODE> </CODE>ic<CODE> </CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>process<CODE> </CODE>fd<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>oc<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Unix.out_channel_of_descr<CODE> </CODE>fd<CODE> </CODE><B>in</B><CODE> </CODE><TT>(</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>try</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>request<CODE> </CODE><CODE>=</CODE><CODE> </CODE>self#receive_h<CODE> </CODE>fd<CODE> </CODE><B>in</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>args<CODE> </CODE><CODE>=</CODE><CODE> </CODE>query_string<CODE> </CODE>request<CODE> </CODE><B>in</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>fun_serv<CODE> </CODE>oc<CODE> </CODE>args;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>with</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Http_error<CODE> </CODE>s<CODE> </CODE>-&gt;<CODE> </CODE>Printf.fprintf<CODE> </CODE>oc<CODE> </CODE><CODE>"HTTP error : %s &lt;BR&gt;"</CODE><CODE> </CODE>s<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>|</CODE><CODE> </CODE><CODE>_</CODE><CODE> </CODE>-&gt;<CODE> </CODE>Printf.fprintf<CODE> </CODE>oc<CODE> </CODE><CODE>"Unknown error &lt;BR&gt;"</CODE><CODE> </CODE><TT>)</TT>;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>flush<CODE> </CODE>oc;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Unix.shutdown<CODE> </CODE>fd<CODE> </CODE>Unix<CODE>.</CODE>SHUTDOWN_ALL<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B><BR><CODE> </CODE><B>end</B>;;<BR>

</PRE>
<BR>
<BR>
As we do not expect the servlet to communicate using Objective CAML's special
internal values, we choose the type <I>string</I> as the protocol type. The
functions <TT>of_string</TT> and <TT>to_string</TT> do nothing.


<PRE><BR># <B>module</B><CODE> </CODE>Simple_http_server<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>P_Text_Server<CODE> </CODE><TT>(</TT><B>struct</B><CODE> </CODE><B>type</B><CODE> </CODE>t<CODE> </CODE><CODE>=</CODE><CODE> </CODE>string<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>of_string<CODE> </CODE>x<CODE> </CODE><CODE>=</CODE><CODE> </CODE>x<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>to_string<CODE> </CODE>x<CODE> </CODE><CODE>=</CODE><CODE> </CODE>x<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B><TT>)</TT>;;<BR>

</PRE>

Finally, we write the primary function to launch the service and construct an
instance of the class <I>http_servlet</I>.
<A NAME="CGI_like_server"></A>


<PRE><BR># <B>let</B><CODE> </CODE>cgi_like_server<CODE> </CODE>port_num<CODE> </CODE>fun_serv<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>sv<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>new</B><CODE> </CODE>Simple_http_server.http_servlet<CODE> </CODE>port_num<CODE> </CODE><CODE>3</CODE><CODE> </CODE><CODE> </CODE>fun_serv<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><B>in</B><CODE> </CODE>sv#start;;<BR><CODE>val cgi_like_server : int -&gt; (out_channel -&gt; string array -&gt; unit) -&gt; unit =</CODE><BR><CODE>  &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>

<H4> Testing the Servlet</H4>It is always useful during development to be able to test the parts that are
already built. For this purpose, we build a small HTTP server which sends the
file specified in the HTTP request as is. The function <TT>simple_serv</TT>
sends the file whose name follows the GET request (the second element of the
argument array). The function also displays all of the arguments passed in
the request.


<PRE><BR># <B>let</B><CODE> </CODE>send_file<CODE> </CODE>oc<CODE> </CODE>f<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>ic<CODE> </CODE><CODE>=</CODE><CODE> </CODE>open_in_bin<CODE> </CODE>f<CODE> </CODE><B>in</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>try</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>while</B><CODE> </CODE><B>true</B><CODE> </CODE><B>do</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>output_byte<CODE> </CODE>oc<CODE> </CODE><TT>(</TT>input_byte<CODE> </CODE>ic<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>done</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>with</B><CODE> </CODE>End_of_file<CODE> </CODE>-&gt;<CODE> </CODE>close_in<CODE> </CODE>ic;;<BR><CODE>val send_file : out_channel -&gt; string -&gt; unit = &lt;fun&gt;</CODE><BR><BR># <B>let</B><CODE> </CODE>simple_serv<CODE> </CODE>oc<CODE> </CODE>args<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>try</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Array.iter<CODE> </CODE><TT>(</TT><B>fun</B><CODE> </CODE>x<CODE> </CODE>-&gt;<CODE> </CODE>print_string<CODE> </CODE><TT>(</TT>x<CODE>^</CODE><CODE>" "</CODE><TT>)</TT><TT>)</TT><CODE> </CODE>args;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>print_newline();<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>send_file<CODE> </CODE>oc<CODE> </CODE>args<CODE>.</CODE><TT>(</TT><CODE>1</CODE><TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>with</B><CODE> </CODE><CODE>_</CODE><CODE> </CODE>-&gt;<CODE> </CODE>Printf.printf<CODE> </CODE><CODE>"error\n"</CODE>;;<BR><CODE>val simple_serv : out_channel -&gt; string array -&gt; unit = &lt;fun&gt;</CODE><BR><BR># <B>let</B><CODE> </CODE>run<CODE> </CODE>n<CODE> </CODE><CODE>=</CODE><CODE> </CODE>cgi_like_server<CODE> </CODE>n<CODE> </CODE>simple_serv;;<BR><CODE>val run : int -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
The command run<CODE> </CODE><CODE>4</CODE><CODE>0</CODE><CODE>0</CODE><CODE>3</CODE> launches this servlet on port 4003. In
addition, we launch a browser to issue a request to load the page
<TT>baro.html</TT> on port 4003. The figure <A HREF="book-ora196.html#fig-http1">21.2</A> shows the
display of the contents of this page in the browser.<BR>
<BR>
<BLOCKQUOTE><DIV ALIGN=center><HR WIDTH="80%" SIZE=2></DIV>
<DIV ALIGN=center>
<IMG SRC="book-ora084.gif">
</DIV>
<BR>
<DIV ALIGN=center>Figure 21.2: HTTP request to an Objective CAML servlet</DIV><BR>

<A NAME="fig-http1"></A>
<DIV ALIGN=center><HR WIDTH="80%" SIZE=2></DIV></BLOCKQUOTE>The browser has sent the request <CODE>GET /baro.html</CODE> to load the page, and
then the request <CODE>GET /canard.gif</CODE> to load the image.

<BR>
<BR>
<A NAME="toc299"></A>
<H3> HTML Servlet Interface</H3>
We will use a CGI-style server to build an HTML-based interface to the
database of chapter <A HREF="index.html#chap-PART1-Applications">6</A> (see page
<A HREF="book-ora057.html#sec-gestassoc">??</A>).<BR>
<BR>
The menu of the function <TT>main</TT> will now be displayed in a form on an
HTML page, providing the same selections. The responses to requests are also
HTML pages, generated dynamically by the servlet. The dynamic page
construction makes use of the utilities defined below.<BR>
<BR>

<H4> Application Protocol</H4>
Our application will use several elements from several protocols:
<OL type=1>
<LI>
 Requests are transmitted from a Web browser to our application server
in the HTTP request format.

<LI> The data items within a request are encoded in the format used by CGI
applications.

<LI> The response to the request is presented as an HTML page.

<LI> Finally, the nature of the request is specified in a format specific
to the application.
</OL>We wish to respond to three kinds of request: queries for the list of mail
addresses, queries for the list of email addresses, and queries for the state
of received fees between two given dates. We give these query
types respectively the names:<BR><CODE>mail_addr</CODE>, <CODE>email_addr</CODE> and
<CODE>fees_state</CODE>. In the last case, we will also transmit two character
strings containing the desired dates. These two dates correspond to the values
of the fields <CODE>start</CODE> and <CODE>end</CODE> on an HTML form.<BR>
<BR>
When a client first connects, the following page is sent. The names of the
requests are encoded within it in the form of HTML anchors.
<A NAME="htmlassoc"></A> 
<PRE>
&lt;HTML&gt;
&lt;TITLE&gt; association &lt;/TITLE&gt;
&lt;BODY&gt;
&lt;HR&gt;
&lt;H1 ALIGN=CENTER&gt;Association&lt;/H1&gt;
&lt;P&gt;
&lt;HR&gt;
&lt;UL&gt;
&lt;LI&gt;List of
&lt;A HREF="http://freres-gras.ufr-info-p6.jussieu.fr:12345/mail_addr"&gt;
mail addresses
&lt;/A&gt;
&lt;LI&gt;List of
&lt;A HREF="http://freres-gras.ufr-info-p6.jussieu.fr:12345/email_addr"&gt;
email addresses
&lt;/A&gt;
&lt;LI&gt;State of received fees&lt;BR&gt;
&lt;FORM 
 method="GET" 
 action="http://freres-gras.ufr-info-p6.jussieu.fr:12345/fees_state"&gt;
Start date : &lt;INPUT type="text" name="start" value=""&gt;
End date : &lt;INPUT type="text" name="end" value=""&gt;
&lt;INPUT name="action" type="submit" value="Send"&gt;
&lt;/FORM&gt;
&lt;/UL&gt;
&lt;HR&gt;
&lt;/BODY&gt;
&lt;/HTML&gt;
</PRE>We assume that this page is contained in the file <CODE>assoc.html</CODE>.<BR>
<BR>

<H4> HTML Primitives</H4>
The HTML utility functions are grouped together into a single class called
<TT>print</TT>. It has a field specifying the output channel. Thus, it can
be used just as well in a CGI application (where the output channel is the
standard output) as in an application using the HTTP server defined in the
previous section (where the output channel is a network socket).<BR>
<BR>
The proposed methods essentially allow us to encapsulate text within HTML
tags. This text is either passed directly as an argument to the method in
the form of a character string, or produced by a function. For example,
the principal method <TT>page</TT> takes as its first argument a string
corresponding to the header of the page<A NAME="text49" HREF="book-ora197.html#note49"><SUP><FONT SIZE=2>1</FONT></SUP></A>, and as its second argument
a function that prints out the contents of the page. The method <TT>page</TT>
produces the tags corresponding to the HTML protocol.<BR>
<BR>
The names of the methods match the names of the corresponding HTML tags, with
additional options added in some cases.


<PRE><BR># <B>class</B><CODE> </CODE>print<CODE> </CODE><TT>(</TT>oc0<CODE>:</CODE>out_channel<TT>)</TT><CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>object</B><TT>(</TT>self<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>val</B><CODE> </CODE>oc<CODE> </CODE><CODE>=</CODE><CODE> </CODE>oc0<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>flush<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><CODE> </CODE>flush<CODE> </CODE>oc<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>str<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Printf.fprintf<CODE> </CODE>oc<CODE> </CODE><CODE>"%s"</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>page<CODE> </CODE>header<CODE> </CODE><TT>(</TT>body<CODE>:</CODE>unit<CODE> </CODE>-&gt;<CODE> </CODE>unit<TT>)</TT><CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Printf.fprintf<CODE> </CODE>oc<CODE> </CODE><CODE>"&lt;HTML&gt;&lt;HEAD&gt;&lt;TITLE&gt;%s&lt;/TITLE&gt;&lt;/HEAD&gt;\n&lt;BODY&gt;"</CODE><CODE> </CODE>header;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>body();<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Printf.fprintf<CODE> </CODE>oc<CODE> </CODE><CODE>"&lt;/BODY&gt;\n&lt;/HTML&gt;\n"</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>p<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Printf.fprintf<CODE> </CODE>oc<CODE> </CODE><CODE>"\n&lt;P&gt;\n"</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>br<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Printf.fprintf<CODE> </CODE>oc<CODE> </CODE><CODE>"&lt;BR&gt;\n"</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>hr<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Printf.fprintf<CODE> </CODE>oc<CODE> </CODE><CODE>"&lt;HR&gt;\n"</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>hr<CODE> </CODE>()<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Printf.fprintf<CODE> </CODE>oc<CODE> </CODE><CODE>"\n&lt;HR&gt;\n"</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>h<CODE> </CODE>i<CODE> </CODE>s<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Printf.fprintf<CODE> </CODE>oc<CODE> </CODE><CODE>"&lt;H%d&gt;%s&lt;/H%d&gt;"</CODE><CODE> </CODE>i<CODE> </CODE>s<CODE> </CODE>i<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>h_center<CODE> </CODE>i<CODE> </CODE>s<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Printf.fprintf<CODE> </CODE>oc<CODE> </CODE><CODE>"&lt;H%d ALIGN=\"CENTER\"&gt;%s&lt;/H%d&gt;"</CODE><CODE> </CODE>i<CODE> </CODE>s<CODE> </CODE>i<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>form<CODE> </CODE>url<CODE> </CODE><TT>(</TT>form_content<CODE>:</CODE>unit<CODE> </CODE>-&gt;<CODE> </CODE>unit<TT>)</TT><CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Printf.fprintf<CODE> </CODE>oc<CODE> </CODE><CODE>"&lt;FORM method=\"post\" action=\"%s\"&gt;\n"</CODE><CODE> </CODE>url;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>form_content<CODE> </CODE>();<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Printf.fprintf<CODE> </CODE>oc<CODE> </CODE><CODE>"&lt;/FORM&gt;"</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>input_text<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Printf.fprintf<CODE> </CODE>oc<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>"&lt;INPUT type=\"text\" name=\"%s\" size=\"%d\" value=\"%s\"&gt;\n"</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>input_hidden_text<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Printf.fprintf<CODE> </CODE>oc<CODE> </CODE><CODE>"&lt;INPUT type=\"hidden\" name=\"%s\" value=\"%s\"&gt;\n"</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>input_submit<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Printf.fprintf<CODE> </CODE>oc<CODE> </CODE><CODE>"&lt;INPUT name=\"%s\" type=\"submit\" value=\"%s\"&gt;"</CODE><CODE> </CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>input_radio<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Printf.fprintf<CODE> </CODE>oc<CODE> </CODE><CODE>"&lt;INPUT type=\"radio\" name=\"%s\" value=\"%s\"&gt;\n"</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>input_radio_checked<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Printf.fprintf<CODE> </CODE>oc<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>"&lt;INPUT type=\"radio\" name=\"%s\" value=\"%s\" CHECKED&gt;\n"</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>option<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Printf.fprintf<CODE> </CODE>oc<CODE> </CODE><CODE>"&lt;OPTION&gt; %s\n"</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>option_selected<CODE> </CODE>opt<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Printf.fprintf<CODE> </CODE>oc<CODE> </CODE><CODE>"&lt;OPTION SELECTED&gt; %s"</CODE><CODE> </CODE>opt<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>select<CODE> </CODE>name<CODE> </CODE>options<CODE> </CODE>selected<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Printf.fprintf<CODE> </CODE>oc<CODE> </CODE><CODE>"&lt;SELECT name=\"%s\"&gt;\n"</CODE><CODE> </CODE>name;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>List.iter<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><TT>(</TT><B>fun</B><CODE> </CODE>s<CODE> </CODE>-&gt;<CODE> </CODE><B>if</B><CODE> </CODE>s<CODE>=</CODE>selected<CODE> </CODE><B>then</B><CODE> </CODE>self#option_selected<CODE> </CODE>s<CODE> </CODE><B>else</B><CODE> </CODE>self#option<CODE> </CODE>s<TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>options;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Printf.fprintf<CODE> </CODE>oc<CODE> </CODE><CODE>"&lt;/SELECT&gt;\n"</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>method</B><CODE> </CODE>options<CODE> </CODE>selected<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>List.iter<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><TT>(</TT><B>fun</B><CODE> </CODE>s<CODE> </CODE>-&gt;<CODE> </CODE><B>if</B><CODE> </CODE>s<CODE>=</CODE>selected<CODE> </CODE><B>then</B><CODE> </CODE>self#option_selected<CODE> </CODE>s<CODE> </CODE><B>else</B><CODE> </CODE>self#option<CODE> </CODE>s<TT>)</TT><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>end</B><CODE> </CODE>;;<BR>

</PRE>

We will assume that these utilities are provided by the module
<TT>Html_frame</TT>.<BR>
<BR>
<A NAME="toc300"></A>
<H3> Dynamic Pages for Managing the Association Database</H3>
For each of the three kinds of request, the application must construct a page
in response. For this purpose we use the utility module <TT>Html_frame</TT>
given above. This means that the pages are not really constructed, but that
their various components are emitted sequentially on the output channel. <BR>We provide an additional (virtual) page to be returned in response to a
request that is invalid or not understood.<BR>
<BR>

<H5> Error page</H5>
The function <TT>print_error</TT> takes as arguments a function for emitting
an HTML page (i.e., an instance of the class <TT>print</TT>) and a
character string containing the error message.<BR>
<BR>


<PRE><BR># <B>let</B><CODE> </CODE>print_error<CODE> </CODE><TT>(</TT>print<CODE>:</CODE>Html_frame.print<TT>)</TT><CODE> </CODE>s<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>print_body()<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>print#str<CODE> </CODE>s;<CODE> </CODE>print#br()<BR><CODE> </CODE><CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>print#page<CODE> </CODE><CODE>"Error"</CODE><CODE> </CODE>print_body<CODE> </CODE>;;<BR><CODE>val print_error : Html_frame.print -&gt; string -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
All of our functions for emitting responses to requests will take as their
first argument a function for emitting an HTML page.<BR>
<BR>

<H5> List of mail addresses</H5>
To obtain the page giving the response to a query for the list of mail
addresses, we will format the list of character strings obtained by the
function <TT>mail_addresses</TT>, which was defined as part of the database
(see page <A HREF="book-ora057.html#sec-listes-adresses">??</A>). We will assume that this function,
and all others directly involving requests to the database, have been defined
in a module named <TT>Assoc</TT>.<BR>
<BR>
To emit this list, we use a function for outputting simple lines:


<PRE><BR># <B>let</B><CODE> </CODE>print_lines<CODE> </CODE><TT>(</TT>print<CODE>:</CODE>Html_frame.print<TT>)</TT><CODE> </CODE>ls<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>print_line<CODE> </CODE>l<CODE> </CODE><CODE>=</CODE><CODE> </CODE><CODE> </CODE>print#str<CODE> </CODE>l;<CODE> </CODE>print#br()<CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>List.iter<CODE> </CODE>print_line<CODE> </CODE>ls<CODE> </CODE>;;<BR><CODE>val print_lines : Html_frame.print -&gt; string list -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
The function for responding to a query for the list of mail addresses is:


<PRE><BR># <B>let</B><CODE> </CODE>print_mail_addresses<CODE> </CODE>print<CODE> </CODE>db<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>print#page<CODE> </CODE><CODE>"Mail addresses"</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><TT>(</TT><B>fun</B><CODE> </CODE>()<CODE> </CODE>-&gt;<CODE> </CODE>print_lines<CODE> </CODE>print<CODE> </CODE><TT>(</TT>Assoc.mail_addresses<CODE> </CODE>db<TT>)</TT><TT>)</TT><BR><CODE> </CODE><CODE> </CODE>;;<BR><CODE>val print_mail_addresses : Html_frame.print -&gt; Assoc.data_base -&gt; unit =</CODE><BR><CODE>  &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
In addition to the parameter for emitting a page, the function
<TT>print_mail_addresses</TT> takes the database as its second parameter.<BR>
<BR>

<H5> List of email addresses</H5>
This function is built on the same principles as that giving the list of mail
addresses, except that it calls the function <TT>email_addresses</TT> from
the module <TT>Assoc</TT>:


<PRE><BR># <B>let</B><CODE> </CODE>print_email_addresses<CODE> </CODE>print<CODE> </CODE>db<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>print#page<CODE> </CODE><CODE>"Email addresses"</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><TT>(</TT><B>fun</B><CODE> </CODE>()<CODE> </CODE>-&gt;<CODE> </CODE>print_lines<CODE> </CODE>print<CODE> </CODE><TT>(</TT>Assoc.email_addresses<CODE> </CODE>db<TT>)</TT><TT>)</TT><CODE> </CODE>;;<BR><CODE>val print_email_addresses : Html_frame.print -&gt; Assoc.data_base -&gt; unit =</CODE><BR><CODE>  &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>

<H5> State of received fees</H5>
The same principle also governs the definition of this function: retrieving
the data corresponding to the request (which here is a pair), then emitting
the corresponding character strings.


<PRE><BR># <B>let</B><CODE> </CODE>print_fees_state<CODE> </CODE>print<CODE> </CODE>db<CODE> </CODE>d1<CODE> </CODE>d2<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>ls<CODE>,</CODE><CODE> </CODE>t<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Assoc.fees_state<CODE> </CODE>db<CODE> </CODE>d1<CODE> </CODE>d2<CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>page_body()<CODE> </CODE><CODE>=</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>print_lines<CODE> </CODE>print<CODE> </CODE>ls;<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>print#str<CODE> </CODE><TT>(</TT><CODE>"Total : "</CODE><CODE>^</CODE><TT>(</TT>string_of_float<CODE> </CODE>t<TT>)</TT><TT>)</TT>;<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>print#br()<BR><CODE> </CODE><CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE>print#page<CODE> </CODE><CODE>"State of received fees"</CODE><CODE> </CODE>page_body<CODE> </CODE>;;<BR><CODE>val print_fees_state :</CODE><BR><CODE>  Html_frame.print -&gt; Assoc.data_base -&gt; string -&gt; string -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
<A NAME="toc301"></A>
<H3> Analysis of Requests and Response</H3>
We define two functions for producing responses based on an HTTP request. The
first (<TT>print_get_answer</TT>) responds to a request presumed to be
formulated using the GET method of the HTTP protocol. The second
alters the production of the answer according to the actual method that the
request used.<BR>
<BR>
These two functions take as their second argument an array of character
strings containing the elements of the HTTP request as analyzed by the
function <TT>get_query_string</TT> (see page <A HREF="book-ora196.html#get_query_string">??</A>).
The first element of the array contains the method, the second the name of
the database request. <BR>In the case of a query for the state of received fees, the start and end dates
for the request are contained in the two fields of the form associated with
the query. The data from the form are contained in the third field of the
array, which must be decomposed by the function <TT>get_form_content</TT>
(see page <A HREF="book-ora196.html#get_form_content">??</A>).<BR>
<BR>


<PRE><BR># <B>let</B><CODE> </CODE>print_get_answer<CODE> </CODE>print<CODE> </CODE>q<CODE> </CODE>db<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>match</B><CODE> </CODE>q<CODE>.</CODE><TT>(</TT><CODE>1</CODE><TT>)</TT><CODE> </CODE><B>with</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>|</CODE><CODE> </CODE><CODE>"/mail_addr"</CODE><CODE> </CODE>-&gt;<CODE> </CODE>print_mail_addresses<CODE> </CODE>print<CODE> </CODE>db<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>|</CODE><CODE> </CODE><CODE>"/email_addr"</CODE><CODE> </CODE>-&gt;<CODE> </CODE>print_email_addresses<CODE> </CODE>print<CODE> </CODE>db<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>|</CODE><CODE> </CODE><CODE>"/fees_state"</CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>-&gt;<CODE> </CODE><B>let</B><CODE> </CODE>nvs<CODE> </CODE><CODE>=</CODE><CODE> </CODE>get_form_content<CODE> </CODE>q<CODE>.</CODE><TT>(</TT><CODE>2</CODE><TT>)</TT><CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>d1<CODE> </CODE><CODE>=</CODE><CODE> </CODE>List.assoc<CODE> </CODE><CODE>"start"</CODE><CODE> </CODE>nvs<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>and</B><CODE> </CODE>d2<CODE> </CODE><CODE>=</CODE><CODE> </CODE>List.assoc<CODE> </CODE><CODE>"end"</CODE><CODE> </CODE>nvs<CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>print_fees_state<CODE> </CODE>print<CODE> </CODE>db<CODE> </CODE>d1<CODE> </CODE>d2<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>|</CODE><CODE> </CODE><CODE>_</CODE><CODE> </CODE>-&gt;<CODE> </CODE>print_error<CODE> </CODE>print<CODE> </CODE><TT>(</TT><CODE>"Unknown request: "</CODE><CODE>^</CODE>q<CODE>.</CODE><TT>(</TT><CODE>1</CODE><TT>)</TT><TT>)</TT><CODE> </CODE>;;<BR><CODE>val print_get_answer :</CODE><BR><CODE>  Html_frame.print -&gt; string array -&gt; Assoc.data_base -&gt; unit = &lt;fun&gt;</CODE><BR><BR># <B>let</B><CODE> </CODE>print_answer<CODE> </CODE>print<CODE> </CODE>q<CODE> </CODE>db<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>try</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>match</B><CODE> </CODE>q<CODE>.</CODE><TT>(</TT><CODE>0</CODE><TT>)</TT><CODE> </CODE><B>with</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>"GET"</CODE><CODE> </CODE>-&gt;<CODE> </CODE>print_get_answer<CODE> </CODE>print<CODE> </CODE>q<CODE> </CODE>db<BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE>|</CODE><CODE> </CODE><CODE>_</CODE><CODE> </CODE>-&gt;<CODE> </CODE>print_error<CODE> </CODE>print<CODE> </CODE><TT>(</TT><CODE>"Unsupported method: "</CODE><CODE>^</CODE>q<CODE>.</CODE><TT>(</TT><CODE>0</CODE><TT>)</TT><TT>)</TT><CODE> </CODE><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>with</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>e<CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>-&gt;<CODE> </CODE><B>let</B><CODE> </CODE>s<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Array.fold_right<CODE> </CODE><TT>(</TT><CODE>^</CODE><TT>)</TT><CODE> </CODE>q<CODE> </CODE><CODE>""</CODE><CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>print_error<CODE> </CODE>print<CODE> </CODE><TT>(</TT><CODE>"Something wrong with request: "</CODE><CODE>^</CODE>s<TT>)</TT><CODE> </CODE>;;<BR><CODE>val print_answer :</CODE><BR><CODE>  Html_frame.print -&gt; string array -&gt; Assoc.data_base -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
<A NAME="toc302"></A>
<H3> Main Entry Point and Application</H3>
The application is a standalone executable that takes the port number as a
parameter. It reads in the database before launching the server. The main
function is obtained from the function <TT>print_answer</TT> defined above
and from the generic HTTP server function <TT>cgi_like_server</TT> defined
in the previous section (see page <A HREF="book-ora196.html#CGI_like_server">??</A>). The latter
function is located in the module <TT>Servlet</TT>.


<PRE><BR># <B>let</B><CODE> </CODE>get_port_num()<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>if</B><CODE> </CODE><TT>(</TT>Array.length<CODE> </CODE>Sys.argv<TT>)</TT><CODE> </CODE><CODE>&lt;</CODE><CODE> </CODE><CODE>2</CODE><CODE> </CODE><B>then</B><CODE> </CODE><CODE>1</CODE><CODE>2</CODE><CODE>3</CODE><CODE>4</CODE><CODE>5</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>else</B><CODE> </CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>try</B><CODE> </CODE>int_of_string<CODE> </CODE>Sys.argv<CODE>.</CODE><TT>(</TT><CODE>1</CODE><TT>)</TT><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>with</B><CODE> </CODE><CODE>_</CODE><CODE> </CODE>-&gt;<CODE> </CODE><CODE>1</CODE><CODE>2</CODE><CODE>3</CODE><CODE>4</CODE><CODE>5</CODE><CODE> </CODE>;;<BR><CODE>val get_port_num : unit -&gt; int = &lt;fun&gt;</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><BR># <B>let</B><CODE> </CODE>main()<CODE> </CODE><CODE>=</CODE><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>db<CODE> </CODE><CODE>=</CODE><CODE> </CODE>Assoc.read_base<CODE> </CODE><CODE>"assoc.dat"</CODE><CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><B>let</B><CODE> </CODE>assoc_answer<CODE> </CODE>oc<CODE> </CODE>q<CODE> </CODE><CODE>=</CODE><CODE> </CODE>print_answer<CODE> </CODE><TT>(</TT><B>new</B><CODE> </CODE>Html_frame.print<CODE> </CODE>oc<TT>)</TT><CODE> </CODE>q<CODE> </CODE>db<CODE> </CODE><B>in</B><BR><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE><CODE> </CODE>Servlet.cgi_like_server<CODE> </CODE><TT>(</TT>get_port_num()<TT>)</TT><CODE> </CODE>assoc_answer<CODE> </CODE>;;<BR><CODE>val main : unit -&gt; unit = &lt;fun&gt;</CODE><BR>

</PRE>
<BR>
<BR>
To obtain a complete application, we combine the definitions of the display
functions into a file <CODE>httpassoc.ml</CODE>. The file ends with a call to the
function <TT>main</TT>:
<PRE>
main() ;;
</PRE>We can then produce an executable named <CODE>assocd</CODE> using the compilation
command:
<PRE>
ocamlc -thread -custom -o assocd unix.cma threads.cma \
       gsd.cmo servlet.cmo html_frame.cmo string_plus.cmo assoc.cmo \
       httpassoc.ml -cclib -lunix -cclib -lthreads
</PRE>All that's left is to launch the server, load the HTML page<A NAME="text50" HREF="book-ora197.html#note50"><SUP><FONT SIZE=2>2</FONT></SUP></A> contained in the file
<CODE>assoc.html</CODE> given at the beginning of this section (page
<A HREF="book-ora196.html#htmlassoc">??</A>), and click.<BR>
<BR>
The figure <A HREF="book-ora196.html#fig-http2">21.3</A> shows an example of the application in use.
<BLOCKQUOTE><DIV ALIGN=center><HR WIDTH="80%" SIZE=2></DIV>
<DIV ALIGN=center>
<IMG SRC="book-ora085.gif">
</DIV>
<BR>
<DIV ALIGN=center>Figure 21.3: HTTP request to an Objective CAML servlet</DIV><BR>

<A NAME="fig-http2"></A>
<DIV ALIGN=center><HR WIDTH="80%" SIZE=2></DIV></BLOCKQUOTE>
The browser establishes an initial connection with the servlet, which sends it
the menu page. Once the entry fields are filled in, the user sends a new
request which contains the data entered. The server decodes the request and
calls on the association database to retrieve the desired information. The
result is translated into HTML and sent to the client, which then displays
this new page.<BR>
<BR>
<A NAME="toc303"></A>
<H3>To Learn More</H3>This application has numerous possible enhancements. First of all, the HTTP
protocol used here is overly simple compared to the new versions, which add a
header supplying the type and length of the page being sent. Likewise, the
method <TT>POST</TT>, which allows modification of the server, is not
supported.<A NAME="text51" HREF="book-ora197.html#note51"><SUP><FONT SIZE=2>3</FONT></SUP></A><BR>
<BR>
To be able to describe the type of a page to be returned, the servlet would
have to support the MIME convention, which is used for describing documents
such as those attached to email messages.<BR>
<BR>
The transmission of images, such as in figure <A HREF="book-ora196.html#fig-http1">21.2</A>, makes it
possible to construct interfaces for 2-player games (see chapter
<A HREF="index.html#chap-PART3-Applications">17</A>), where one associates links with drawings of
positions to be played. Since the server knows which moves are legal, only
the valid positions are associated with links.<BR>
<BR>
The MIME extension also allows defining new types of data. One can thus
support a private protocol for Objective CAML values by defining a new MIME type.
These values will be understandable only by an Objective CAML program using the
same private protocol. In this way, a request by a client for a remote
Objective CAML value can be issued via HTTP. One can even pass a serialized closure
as an argument within an HTTP request. This, once reconstructed on the server
side, can be executed to provide the desired result.


<BR>
<BR>

<BR>
<BR>
<HR>
<A HREF="book-ora195.html"><IMG SRC ="previous_motif.gif" ALT="Previous"></A>
<A HREF="index.html"><IMG SRC ="contents_motif.gif" ALT="Contents"></A>
<A HREF="book-ora198.html"><IMG SRC ="next_motif.gif" ALT="Next"></A>
</BODY>
</HTML>
